package cn.qingfeng.a003_chat_v2_1.javafxview;

import cn.qingfeng.a003_chat_v2_1.message.ChatResponseMessage;
import cn.qingfeng.a003_chat_v2_1.message.LoginResponseMessage;
import cn.qingfeng.a003_chat_v2_1.protocol.MessageCodoc;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import javafx.application.Platform;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 根据ChatClient改进，可以灵活取用channel
 */
//@Slf4j
public class ChatClientRenovation {
    static AtomicBoolean LOGIN_FLAG = new AtomicBoolean(false);
    static CountDownLatch WAIT_FOR_ACTIVE = new CountDownLatch(1);
    static CountDownLatch WAIT_FOR_LOGIN = new CountDownLatch(1);
    static AtomicReference<ChannelHandlerContext> channelHandlerContextAtomicReference = new AtomicReference<>();
    static AtomicReference<String> receiveContent = new AtomicReference<>();

    public static Channel init() throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.group(group);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel sc) throws Exception {
//                    sc.pipeline().addLast(new StringEncoder());
                    sc.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
//                    sc.pipeline().addLast(new StringDecoder());
                    sc.pipeline().addLast(new MessageCodoc());

                    sc.pipeline().addLast(new SimpleChannelInboundHandler<LoginResponseMessage>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, LoginResponseMessage msg) throws Exception {
                            try {
                                System.out.println(msg);
                                if ("登录成功".equals(msg.getContent())) {
                                    LOGIN_FLAG.set(true);
                                }
                                // 让计数变为0，然后就能唤醒await处的进程了
                                WAIT_FOR_LOGIN.countDown();
                            } catch (Exception e) {
                                e.printStackTrace();
                                throw e;
                            }
                        }
                    });

                    sc.pipeline().addLast(new SimpleChannelInboundHandler<ChatResponseMessage>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, ChatResponseMessage msg) throws Exception {
                            try {
                                System.out.println(msg);
                                // Platform.runLater不加的话会报如下错误：
                                // - Exception in thread "nioEventLoopGroup-2-1" java.lang.IllegalStateException: Not on FX application thread; currentThread = nioEventLoopGroup-2-1
                                // - 但是这个错误不想影响功能实现。
                                // - Platform.runLater(Runnable) 方法来将任务提交给 JavaFX 线程
                                Platform.runLater(() -> {
                                    QQDialogApp.controller.receiveContent(msg.getFromUsername() + "：" + msg.getContent());
                                });
                            } catch (Exception e) {
                                e.printStackTrace();
                                throw e;
                            }
                        }
                    });
                }
            });
            ChannelFuture channelFuture = bootstrap.connect("localhost", 8080).sync();
            Channel channel = channelFuture.channel();
            channelFuture.addListener(future -> {
                if (future.isSuccess()) {
                    System.out.println("Connected successfully.");
                } else {
                    System.err.println("Failed to connect.");
                    future.cause().printStackTrace();
                    // 如果连接失败，关闭通道并优雅地关闭 EventLoopGroup
                    if (channel != null) {
                        channel.close().syncUninterruptibly();
                    }
                    group.shutdownGracefully();
                }
            });
            return channel;
        } finally {

        }
    }
}
